跳到主要内容

简介

传输控制协议( TCP , Transmission Control Protocol )是一种面向连接的、可靠的、基于字节流的传输层通信协议,由 IETF 的 RFC 793 定义。

TCP 旨在适应支持多网络应用的分层协议层次结构。 连接到不同但互连的计算机通信网络的主计算机中的成对进程之间依靠 TCP 提供可靠的通信服务。 TCP 假设它可以从较低级别的协议获得简单的,可能不可靠的数据报服务。 原则上, TCP 应该能够在从硬线连接到分组交换或电路交换网络的各种通信系统之上操作。

传输控制协议( TCP , Transmission Control Protocol )是为了在不可靠的互联网络上提供可靠的端到端字节流而专门设计的一个传输协议。

功能

应用层向 TCP 层发送用于网间传输的、用 8 位字节表示的数据流,然后 TCP 把数据流分区成适当长度的报文段(通常受该计算机连接的网络的数据链路层的最大传输单元( MTU )的限制)。之后 TCP 把结果包传给 IP 层,由它来通过网络将包传送给接收端实体的 TCP 层。 TCP 为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的包发回一个相应的确认( ACK );如果发送端实体在合理的往返时延( RTT )内未收到确认,那么对应的数据包就被假设为已丢失将会被进行重传。 TCP 用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。

每台支持 TCP 的机器都有一个 TCP 传输实体。 TCP 实体可以是一个库过程、一个用户进程,或者内核的一部分。在所有这些情形下,它管理 TCP 流,以及与 IP 层之间的接口。 TCP 传输实体接受本地进程的用户数据流,将它们分割成不超过 64KB (实际上去掉 IP 和 TCP 头,通常不超过 1460 数据字节)的分段,每个分段以单独的 IP 数据报形式发送。当包含 TCP 数据的数据报到达一台机器时,它们被递交给 TCP 传输实体, TCP 传输实体重构出原始的字节流。为简化起见,我们有时候仅仅用“ TCP ”来代表 TCP 传输实体(一段软件)或者 TCP 协议(一组规则)。根据上下文语义你应该能很消楚地推断出其实际含义。例如,在“用户将数据交给 TCP ”这句话中,很显然这里指的是 TCP 传输实体。

IP 层并不保证数据报一定被正确地递交到接收方,也不指示数据报的发送速度有多快。正是 TCP 负责既要足够快地发送数据报,以便使用网络容量,但又不能引起网络拥塞:而且, TCP 超时后,要重传没有递交的数据报。即使被正确递交的数据报,也可能存在错序的问题,这也是 TCP 的责任,它必须把接收到的数据报重新装配成正确的顺序。简而言之, TCP 必须提供可靠性的良好性能,这正是大多数用户所期望的而 IP 又没有提供的功能。

TCP 为了保证报文传输的可靠,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的字节发回一个相应的确认( ACK );如果发送端实体在合理的往返时延( RTT )内未收到确认,那么对应的数据(假设丢失了)将会被重传。

  • 在数据正确性与合法性上, TCP 用一个校验和函数来检验数据是否有错误,在发送和接收时都要计算校验和,同时可以使用 md5 认证对数据进行加密
  • 在保证可靠性上,采用超时重传和捎带确认机制
  • 在流量控制上,采用滑动窗口协议,协议中规定,对于窗口内未经确认的分组需要重传

AIMD 算法

在拥塞控制上,采用广受好评的 TCP 拥塞控制算法 。该算法主要包括四个主要部分

慢启动

每当建立一个 TCP 连接时或一个 TCP 连接发生超时重传后,该连接便进入慢启动阶段。进入慢启动后, TCP 实体将拥塞窗口的大小初始化为一个报文段,即: cwnd=1 。此后,每收到一个报文段的确认( ACK ), cwnd 值加 1 ,即拥塞窗口按指数增加。当 cwnd 值超过慢启动阐值( ssthresh )或发生报文段丢失重传时,慢启动阶段结束。前者进入拥塞避免阶段,后者重新进入慢启动阶段

拥塞避免

在慢启阶段,当 cwnd 值超过慢启动阐值( ssthresh )后,慢启动过程结束, TCP 连接进入拥塞避免阶段。在拥塞避免阶段,每一次发送的 cwnd 个报文段被完全确认后,才将 cwnd 值加 1 。在此阶段, cwnd 值线性增加

快速重传

快速重传是对超时重传的改进。当源端收到对同一个报文的三个重复确认时,就确定一个报文段已经丢失,因此立刻重传丢失的报文段,而不必等到重传定时器( RTO )超时。以此减少不必要的等待时间

快速恢复

快速恢复是对丢失恢复机制的改进。在快速重传之后,不经过慢启动过程而直接进入拥塞避免阶段。每当快速重传后,置 ssthresh=cwnd/2 、 ewnd=ssthresh+3 。此后,每收到一个重复确认,将 cwnd 值加 1 ,直至收到对丢失报文段和其后若干报文段的累积确认后,置 cwnd=ssthresh ,进入拥塞避免阶段

规定

  • 数据分片:在发送端对用户数据进行分片,在接收端进行重组,由 TCP 确定分片的大小并控制分片和重组
  • 到达确认:接收端接收到分片数据时,根据分片数据序号向发送端发送一个确认
  • 超时重发:发送方在发送分片时启动超时定时器,如果在定时器超时之后没有收到相应的确认,重发分片
  • 滑动窗口: TCP 连接每一方的接收缓冲空间大小都固定,接收端只允许另一端发送接收端缓冲区所能接纳的数据, TCP 在滑动窗口的基础上提供流量控制,防止较快主机致使较慢主机的缓冲区溢出
  • 失序处理:作为 IP 数据报来传输的 TCP 分片到达时可能会失序, TCP 将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层
  • 重复处理:作为 IP 数据报来传输的 TCP 分片会发生重复, TCP 的接收端必须丢弃重复的数据
  • 数据校验: TCP 将保持它首部和数据的检验和,这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到分片的检验和有差错, TCP 将丢弃这个分片,并不确认收到此报文段导致对端超时并重发

首部格式

  • -Source Port 是源端口, 16 位
  • ---Destination Port 是目的端口, 16 位
  • ---Sequence Number 是发送数据包中的第一个字节的序列号, 32 位
  • ---Acknowledgment Number 是确认序列号, 32 位
  • ---Data Offset 是数据偏移, 4 位,该字段的值是 TCP 首部(包括选项)长度除以 4
  • --- 标志位: 6 位, URG 表示 Urgent Pointer 字段有意义:
  • ACK 表示 Acknowledgment Number 字段有意义
  • PSH 表示 Push 功能, RST 表示复位 TCP 连接
  • SYN 表示 SYN 报文(在建立 TCP 连接的时候使用)
  • FIN 表示没有数据需要发送了(在关闭 TCP 连接的时候使用)
  • Window 表示接收缓冲区的空闲空间, 16 位,用来告诉 TCP 连接对端自己能够接收的最大数据长度
  • ---Checksum 是校验和, 16 位
  • ---Urgent Pointers 是紧急指针, 16 位,只有 URG 标志位被设置时该字段才有意义,表示紧急数据相对序列号( Sequence Number 字段的值)的偏移

工作方式

建立链接

TCP 是因特网中的传输层协议,使用三次握手协议建立连接。当主动方发出 SYN 连接请求后,等待对方回答 SYN+ACK ,并最终对对方的 SYN 执行 ACK 确认。这种建立连接的方法可以防止产生错误的连接, TCP 使用的流量控制协议是可变大小的滑动窗口协议。

连接终止

建立一个连接需要三次握手,而终止一个连接要经过四次握手,这是由 TCP 的半关闭( half-close )造成的。

  • 某个应用进程首先调用 close ,称该端执行“主动关闭”( active close )。该端的 TCP 于是发送一个 FIN 分节,表示数据发送完毕
  • 接收到这个 FIN 的对端执行 “被动关闭”( passive close ),这个 FIN 由 TCP 确认
  • 一段时间后,接收到这个文件结束符的应用进程将调用 close 关闭它的套接字。这导致它的 TCP 也发送一个 FIN
  • 接收这个最终 FIN 的原发送端 TCP (即执行主动关闭的那一端)确认这个 FIN

无论是客户还是服务器,任何一端都可以执行主动关闭。通常情况是,客户执行主动关闭,但是某些协议,例如, HTTP/1.0 却由服务器执行主动关闭。

可靠性

TCP 提供一种面向连接的、可靠的字节流服务。面向连接意味着两个使用 TCP 的应用(通常是一个客户和一个服务器)在彼此交换数据包之前必须先建立一个 TCP 连接。这一过程与打电话很相似,先拨号振铃,等待对方摘机说“喂”,然后才说明是谁。在一个 TCP 连接中,仅有两方进行彼此通信。广播和多播不能用于 TCP 。

  • 应用数据被分割成 TCP 认为最适合发送的数据块。这和 UDP 完全不同,应用程序产生的数据长度将保持不变。由 TCP 传递给 IP 的信息单位称为报文段或段( segment )

  • 当 TCP 发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。当 TCP 收到发自 TCP 连接另一端的数据,它将发送一个确认。 TCP 有延迟确认的功能,在此功能没有打开,则是立即确认。功能打开,则由定时器触发确认时间点

  • TCP 将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错, TCP 将丢弃这个报文段和不确认收到此报文段(希望发端超时并重发)

  • TCP 报文段作为 IP 数据报来传输,而 IP 数据报的到达可能会失序,因此 TCP 报文段的到达也可能会失序。如果必要, TCP 将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层

  • IP 数据报会发生重复, TCP 的接收端必须丢弃重复的数据

  • TCP 还能提供流量控制。 TCP 连接的每一方都有固定大小的缓冲空间。 TCP 的接收端只允许另一端发送接收端缓冲区所能接纳的数据。这将防止较快主机致使较慢主机的缓冲区溢出

两个应用程序通过 TCP 连接交换 8bit 字节构成的字节流。 TCP 不在字节流中插入记录标识符。我们将这称为字节流服务( byte stream service )。如果一方的应用程序先传 10 字节,又传 20 字节,再传 50 字节,连接的另一方将无法了解发方每次发送了多少字节。只要自己的接收缓存没有塞满, TCP 接收方将有多少就收多少。一端将字节流放到 TCP 连接上,同样的字节流将出现在 TCP 连接的另一端。

TCP 不知道传输的数据字节流是二进制数据,还是 ASC Ⅱ字符、 EBCDIC 字符或者其他类型数据。对字节流的解释由 TCP 连接双方的应用层解释。

重传策略

TCP 协议用于控制数据段是否需要重传的依据是设立重发定时器。在发送一个数据段的同时启动一个重传,如果在重传超时前收到确认( Acknowlegement )就关闭该重传,如果重传超时前没有收到确认,则重传该数据段。在选择重发时间的过程中, TCP 必须具有自适应性。它需要根据互联网当时的通信情况,给出合适的重发时间。

配置 TCP

修改建立 TCP 连接的超时时间

使用 no ip tcp syntime-out 命令恢复参数缺省值

修改缓冲区大小

TCP 的接收缓冲区是用来缓存从对端接收到的数据,这些数据后续会被应用程序读取。一般情况下, TCP 报文的窗口值反映接收缓冲区的空闲空间的大小。对于带宽比较大、有大批量数据的连接,增大接收缓冲区的大小可以显著提供 TCP 传输性能。 TCP 的发送缓冲区是用来缓存应用程序的数据,发送缓冲区的每个字节都有序列号,被应答确认的序列号对应的数据会从发送缓冲区删除掉。增大发送缓冲区可以提高 TCP 跟应用程序的交互能力,也因此会提高性能。但是增大接收和发送缓冲区会导致 TCP 占用比较多的内存。

使用 no ip tcp window-size 命令恢复接收和发送缓冲区大小为缺省值。

禁止端口不可达时的重置报文

TCP 模块在分发 TCP 报文时,如果找不到该报文所属的 TCP 连接会主动回复一个 reset 报文以终止对端的 TCP 连接。攻击者可能利用大量的端口不可达的 TCP 报文对设备进行攻击。

使用 no ip tcp not-send-rst 命令恢复发送 reset 报文。

限制 TCP 连接的 MSS 的最大值

MSS 是最大传输段大小的缩写,指一个 TCP 报文的数据载荷的最大长度,不包括 TCP 选项。

在 TCP 建立连接的三次握手中,有一种很重要的工作那就是进行 MSS 协商。连接的双方都在 SYN 报文中增加 MSS 选项,其选项值表示本端最大能接收的段大小,即对端最大能发送的段大小。连接的双方取本端发送的 MSS 值和接收对端的 MSS 值的较小者作为本连接最大传输段大小。

使用 no ip tcp mss 命令取消此限制。

启用 PMTU 发现功能

TCP 的路径最大传输单元( PMTU )发现功能是按 RFC1191 实现的,这个功能可以提高网络带宽的利用率。当用户使用 TCP 来批量传输大块数据时,该功能可以使传输性能得到明显提升。

使用 no ip tcp path-mtu-discovery 命令关闭 PMTU 发现功能。

设置接口收发 SYN 报文的 MSS 选项值

使用 no ip tcp adjust-mss 命令取消此项设置,则接口收发 SYN 报文时,不会修改报文的 MSS 选项值。

协议对比

TCP 是面向连接的传输控制协议,而 UDP 提供了无连接的数据报服务; TCP 具有高可靠性,确保传输数据的正确性,不出现丢失或乱序; UDP 在传输数据前不建立连接,不对数据报进行检查与修改,无须等待对方的应答,所以会出现分组丢失、重复、乱序,应用程序需要负责传输可靠性方面的所有工作; UDP 具有较好的实时性,工作效率较 TCP 协议高; UDP 段结构比 TCP 的段结构简单,因此网络开销也小。 TCP 协议可以保证接收端毫无差错地接收到发送端发出的字节流,为应用程序提供可靠的通信服务。对可靠性要求高的通信系统往往使用 TCP 传输数据。比如 HTTP 运用 TCP 进行数据的传输。

TCP 短连接

客户端向服务器发起连接请求,服务器接到请求,然后双方建立连接。客户端向服务器 发送消息,服务器回应客户端,然后一次读写就完成了,这时候双方任何一个都可以发起 close 操作,不过一般都是客户端先发起 close 操作。

短连接的优点是:管理起来比较简单,存在的连接都是有用的连接,不需要额外的控制手段

TCP 长连接

客户端向服务器发起连接,服务器接受客户端连接,双方建立连接。客户端与服务器完成一次读写之后,它们之间的连接并不会主动关闭,后续的读写操作会继续使用这个连接。

如果一个给定的连接在两小时内没有任何的动作,则服务器就向客户发一个探测报文段,客户主机必须处于以下 4 个状态之一:

  • 客户主机依然正常运行,并从服务器可达。客户的 TCP 响应正常,而服务器也知道对方是正常的,服务器在两小时后将保活定时器复位
  • 客户主机已经崩溃,并且关闭或者正在重新启动。在任何一种情况下,客户的 TCP 都没有响应。服务端将不能收到对探测的响应,并在 75 秒后超时。服务器总共发送 10 个这样的探测 ,每个间隔 75 秒。如果服务器没有收到一个响应,它就认为客户主机已经关闭并终止连接
  • 客户主机崩溃并已经重新启动。服务器将收到一个对其保活探测的响应,这个响应是一个复位,使得服务器终止这个连接
  • 客户机正常运行,但是服务器不可达,这种情况与 2 类似, TCP 能发现的就是没有收到探查的响应

在长连接的应用场景下,客户端端一般不会主动关闭它们之间的连接,客户端与服务器之间的连接如果一直不关闭的话,会存在一个问 题,随着客户端连接越来越多,服务器早晚有扛不住的时候,这时候服务器端需要采取一些策略,如关闭一些长时间没有读写事件发生的连接,这样可 以避免一些恶意连接导致服务器端服务受损;如果条件再允许就可以以客户端机器为颗粒度,限制每个客户端的最大长连接数,这样可以完全避免某个蛋疼的 客户端连累后端服务。

选择

长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况,。每个 TCP 连接都需要三步握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降低很多,所以每个操作完后都不断开,次处理时直接发送数据包就 OK 了,不用建立 TCP 连接。

而像 WEB 网站的 http 服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,而像 WEB 网站这么频繁的成千上万甚至上亿客户端的 连接用短连接会更省一些资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那可想而知吧。所以并发量大,但每个用户无需频 繁操作情况下需用短连好。